package com.lei.study.cds.unit3;

import com.lei.study.cds.unit2.MvelCalculateTools;
import org.apache.commons.lang3.StringUtils;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 解析
 * 处理字符串的解析
 *
 * @author 伍磊
 */
public class Parse {

    public static void main(String[] args) {
        String express = "#avg# ( ( #t-2#{CASH} / #t-2#{TASSET} ), ( #t-1#{CASH} / #t-1#{TASSET} ), ({CASH} / {TASSET} ))  >= 0.2\n" +
                "And\n" +
                "(#t-2#{STLOAN}  + #t-1#{STLOAN}  + {STLOAN} ) / (#t-2#{REV}  + #t-1#{REV}  + {REV} )  <= 0.1\n";

        // 1 去除空格
        express = express.trim();

        // 2 去除 {}
        express = express.replaceAll("\\{", "");
        express = express.replaceAll("}", "");

        System.out.println(express);

        System.out.println("--------------");

        // 3 将And转换为 &&
        express = express.replaceAll("And", "&&");
        System.out.println(express);

        System.out.println("--------------");

        // 4 将此方法使用的函数的#去除
        express = express.replaceAll("#avg#", "AVG");
        System.out.println(express);

        System.out.println("--------------");


        // 7 前端会将计算的项目带过来   CASH、TASSET、STLOAN、REV
        // 组装传递参数
        List<String> params = new ArrayList<>();
        params.add("CASH");
        params.add("TASSET");
        params.add("STLOAN");
        params.add("REV");
        // 将这些数据进行计算
        String old = express;
        while (old.contains("#CASH")) {
            String x = StringUtils.substringAfterLast(StringUtils.substringBefore(old, "#CASH"), "#");
            params.add("#" + x + "#CASH");
            old = StringUtils.substringAfter(old, "#CASH");
        }
        if (!old.contains("CASH")) {
            params.remove("CASH");
        }
        String old1 = express;
        while (old1.contains("#TASSET")) {
            String x = StringUtils.substringAfterLast(StringUtils.substringBefore(old1, "#TASSET"), "#");
            params.add("#" + x + "#TASSET");
            old1 = StringUtils.substringAfter(old1, "#TASSET");
        }
        if (!old1.contains("TASSET")) {
            params.remove("TASSET");
        }
        String old2 = express;
        while (old2.contains("#STLOAN")) {
            String x = StringUtils.substringAfterLast(StringUtils.substringBefore(old2, "#STLOAN"), "#");
            params.add("#" + x + "#STLOAN");
            old2 = StringUtils.substringAfter(old2, "#STLOAN");
        }
        if (!old2.contains("STLOAN")) {
            params.remove("STLOAN");
        }

        String old3 = express;
        while (old3.contains("#REV")) {
            String x = StringUtils.substringAfterLast(StringUtils.substringBefore(old3, "#REV"), "#");
            params.add("#" + x + "#REV");
            old3 = StringUtils.substringAfter(old3, "#REV");
        }
        if (!old3.contains("REV")) {
            params.remove("REV");
        }

        System.out.println(params);
        // 5 将衍生标签替换为基础公式 todo

        // 6 将#t-1#进行特殊处理
        // t-1实际上复赋值的时候 是否考虑在赋值的时候进行特殊处理 解析公式的时候将此省略
        // 计算公式需要加全部标签字段 且此字段带着#t-1# 从全部标签字段中获取计算需要传递的参数

        // 将#t-1# #t-2#转换为对应的
        express = express.replaceAll("#t-1#", "R1T0SEP0");
        express = express.replaceAll("#t-2#", "R2T0SEP0");
        System.out.println(express);

        System.out.println("--------------");

        List<String> newParams = new ArrayList<>();
        // 替换参数
        params.forEach(param -> {
            param = param.replaceAll("#t-1#", "R1T0SEP0");
            param = param.replaceAll("#t-2#", "R2T0SEP0");
            newParams.add(param);
        });

        System.out.println(express);
        System.out.println(newParams);

        // 计算
        Map<String, Object> map = new HashMap<>();
        newParams.forEach(param -> map.put(param, new BigDecimal("0.01")));

        System.out.println("计算结果-----------------");

        ParserContext parserContext = MvelCalculateTools.initParse();
        Serializable compiled = MVEL.compileExpression(express, parserContext);
        Object o = MVEL.executeExpression(compiled, map);
        System.out.println(o);
    }
}
